


import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.UIManager;
import javax.swing.SwingUtilities;

public class FC extends JPanel implements MouseListener {
	ArrayList<JLabel> cards;
	ArrayList<JLabel> card_back;
	ArrayList<JLabel> cards_selected;
	JLabel Selected = null;
	
	//FreeCell data
    Cascade[] cascades;
    Cell[] cells;
    Foundation[] foundations;
	
	//GUI Information
	final int Window_H = 600;
    final int Window_W = 900;
    final int Cascade_X = 60;
    final int Cascade_Y = 150;
    final int Cell_X = 10;
    final int Cell_Y = 10;
    final int Foundation_X = 500;
    final int Foundation_Y = 10;
    final int card_h = 96;
    final int card_w = 72;
	
    public FC() {
        setLayout(null);
        setBackground(Color.green);
        setSize(Window_W,Window_H);
        
        init();
        setup();        
    }
    public void setup(){	
		//Start to place them
    	this.removeAll();
		ArrayList<Card> temp = null;
		Card test = null;
		int winner = 0;
		for(int i=0; i<4; i++){
			test = cells[i].get();
			if(test != null){
				add(cards.get(test.getIndex()));
				cards.get(test.getIndex()).setBounds(Cell_X + i*100, Cell_Y, card_w, card_h);
			}else{
				add(card_back.get(i));
				card_back.get(i).setBounds(Cell_X + i*100, Cell_Y, card_w, card_h);
			}
			test = foundations[i].get();
			if(test != null){
				add(cards.get(test.getIndex()));
				cards.get(test.getIndex()).setBounds(Foundation_X + i*100, Foundation_Y, card_w, card_h);
			}else{
				add(card_back.get(i+4));
				card_back.get(i+4).setBounds(Foundation_X + i*100, Foundation_Y, card_w, card_h);
			}
		}
		for(int i=0; i<8; i++){
			temp = cascades[i].getCascade();
			if(temp.size() == 0){
				this.add(card_back.get(i+8));
				card_back.get(i+8).setBounds(Cascade_X + i*100, Cascade_Y, card_w, card_h);
			}
			for(int j=(temp.size()); j>0; j--){
				if(temp.size() != 0){
					if(cards_selected.get(temp.get(j-1).getIndex()) == Selected){
						this.add(cards.get(temp.get(j-1).getIndex()));
						cards.get(temp.get(j-1).getIndex()).setBounds(Cascade_X + i*100, Cascade_Y + (j-1)*25, card_w, card_h);
					}else if(cards.get(temp.get(j-1).getIndex()) != Selected){
						this.add(cards.get(temp.get(j-1).getIndex()));
						cards.get(temp.get(j-1).getIndex()).setBounds(Cascade_X + i*100, Cascade_Y + (j-1)*25, card_w, card_h);
					}else if(cards.get(temp.get(j-1).getIndex()) == Selected){
						this.add(cards_selected.get(temp.get(j-1).getIndex()));
						cards_selected.get(temp.get(j-1).getIndex()).setBounds(Cascade_X + i*100, Cascade_Y + (j-1)*25, card_w, card_h);
					}
				}
			}
		}
		
		//Check for winner
		//check if each foundation is a king
		for(int i=0; i<4; i++)
			if(foundations[i].get() != null)
				if(foundations[i].get().getValue() == 13)
					winner++;
		if(winner == 4){
			JOptionPane.showMessageDialog(null, "You win!");
			System.exit(0);
		}
    }
    public void init(){
    	//Now that everything is loaded, lets set up the game
        Deck deck = new Deck();
        cascades = new Cascade[8];
        cells = new Cell[4];
        foundations = new Foundation[4];
        OrderedCascade temp = null;
        
        Card test = null;
        
        int whichcascade = 0;
        
        for(int i=0; i<8; i++)
        	cascades[i] = new Cascade();
        for(int i=0; i<4; i++){
        	cells[i] = new Cell();
        	foundations[i] = new Foundation();
        }
        for(int i=0; i<52; i++){
        	temp = new OrderedCascade();
        	test = deck.remove();
        	if(temp.add(test)){
        		if(cascades[whichcascade].add(temp, true)){
        			whichcascade++;
        			if(whichcascade>7)
        				whichcascade=0;
        		}
        	}
        }
        
        cards = new ArrayList<JLabel>();
        card_back = new ArrayList<JLabel>();
        cards_selected = new ArrayList<JLabel>();
        try 
        {
        	for(int i=1; i<53; i++){
        		cards.add(new JLabel(new ImageIcon("images/cards/" + i + ".png")));
        		cards.get(i-1).addMouseListener(this);
        		cards_selected.add(new JLabel(new ImageIcon("images/cards/" + i + "h.png")));
        		cards_selected.get(i-1).addMouseListener(this);
        	}
        	for(int i=0; i<16; i++){
        		card_back.add(new JLabel(new ImageIcon("images/cards/b1fv.png")));
        		card_back.get(i).addMouseListener(this);
        	}
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("Free Cell");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(900,600);

        //Add content to the window.
        frame.add(new FC());

        //Display the window.
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event dispatch thread:
        //creating and showing this application's GUI.
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
		//Turn off metal's use of bold fonts
	        UIManager.put("swing.boldMetal", Boolean.FALSE);
                
		createAndShowGUI();
            }
        });
    }
	@Override
	public void mouseClicked(MouseEvent e) {
		
	}
	
	public OrderedCascade getOC(int index){
		ArrayList<Card> temp;
		for(int i=0; i<8; i++){
			temp = cascades[i].getCascade();
			for(int j=0; j<temp.size(); j++)
				if(temp.get(j).getIndex() == index)
					return cascades[i].getOrderedCascade(index);
		}
		return null;
	}
	
	public Cascade getC(int index){
		ArrayList<Card> temp;
		for(int i=0; i<8; i++){
			temp = cascades[i].getCascade();
			for(int j=0; j<temp.size(); j++)
				if(temp.get(j).getIndex() == index)
					return cascades[i];
		}
		return null;
	}
	
	public Cell getCell(int index){
		for(int i=0; i<4; i++)
			if(cells[i].get() != null)
			if(cells[i].get().getIndex() == index)
				return cells[i];
		return null;
	}
	
	public Foundation getFoundation(int index){
		for(int i=0; i<4; i++)
			if(foundations[i].get() != null)
			if(foundations[i].get().getIndex() == index)
				return foundations[i];
		return null;
	}
	
	public int getCindex(int index){
		ArrayList<Card> temp;
		for(int i=0; i<8; i++){
			temp = cascades[i].getCascade();
			for(int j=0; j<temp.size(); j++)
				if(temp.get(j).getIndex() == index)
					return i;
		}
		return -1;
	}
	public int getCellindex(int index){
		for(int i=0; i<4; i++)
			if(cells[i].get() != null)
				if(cells[i].get().getIndex() == index)
					return i;
		return -1;
	}
	
	public int getFoundationindex(int index){
		for(int i=0; i<4; i++)
			if(foundations[i].get().getIndex() == index)
				return i;
		return -1;
	}
		
	public int whereIsCard(int index){
		ArrayList<Card> temp;
		for(int i=0; i<8; i++){
			temp = cascades[i].getCascade();
			for(int j=0; j<temp.size(); j++)
				if(temp.get(j).getIndex() == index)
					return 0;
		}
		for(int i=0; i<4; i++){
			if(cells[i].get() != null)
				if(cells[i].get().getIndex() == index)
					return 1;
			if(foundations[i].get() != null)
				if(foundations[i].get().getIndex() == index)
					return 2;
		}
		return -1;	
	}
	
	@Override
	public void mouseEntered(MouseEvent e) {
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		
	}
	@Override
	public void mousePressed(MouseEvent e) {
		
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		int index1=-1;
		int index2=-1;
		JLabel temp;
		
		Boolean back = false;
		
		Card c1;
		Card c2;
		
		int placeOfCard = -1;
		int placeOfCard2;
		
		OrderedCascade oc = null;
		int c3 = -1;
		Cell cl = null;
		
		int c = -1;
		int cl2 = -1;
		int f = -1;
		
		//JOptionPane.showMessageDialog(null, Selected == null);
		if(Selected == null){
			Selected = (JLabel) e.getComponent();
			index1 = cards.indexOf(Selected);
			if(card_back.indexOf(Selected) != -1)
				Selected = null;
		}else{
			temp = (JLabel) e.getComponent();
			if(temp != Selected){
				index1 = cards.indexOf(Selected);
				if(cards.indexOf(temp) != -1)
					index2 = cards.indexOf(temp);
				else if(cards_selected.indexOf(temp) != -1)
					index2 = cards_selected.indexOf(temp);
				else{
					index2 = card_back.indexOf(temp);
					back = true;
				}
				if(index1 == index2){
					return;
				}
				placeOfCard = whereIsCard(index1);
				if(placeOfCard == 0){
					oc = getOC(index1);
					c3 = getCindex(index1);
				}else if(placeOfCard == 1){
					cl = getCell(index1);
				}
				if(placeOfCard != -1){
					if(!back)
						placeOfCard2 = whereIsCard(index2);
					else{
						if(index2 > 7)
							placeOfCard2 = 5;
						else if(index2>3)
							placeOfCard2 = 4;
						else
							placeOfCard2 = 3;
					}
					if(oc != null){
						if(oc != cascades[c3].getBottom()){
							if(cascades[c3].getBottom() == null)						
								cascades[c3].removeBottom();
							if(cascades[c3].getBottom().getTop() == null)
								cascades[c3].removeBottom();
							Selected = null;
							return;
						}
						if(placeOfCard2 == 0){
							c = getCindex(index2);
						}else if(placeOfCard2 == 1){
							cl2 = getCellindex(index2);
						}else if(placeOfCard2 == 2){
							f = getFoundationindex(index2);
						}
						
						if(placeOfCard2 == -1){
							Selected = null;
							return;
						}
						if(c != -1){
							if(cascades[c].add(oc,false))
								cascades[c3].removeBottom();
						}else if(cl2 != -1){
							if(cells[cl2].add(oc.getTop()))
								oc.removeTop();
							if(cascades[c3].getBottom() == null)
								cascades[c3].removeBottom();
						}else if(f != -1){
							if(foundations[f].add(oc.getTop()))
								oc.removeTop();
							if(cascades[c3].getBottom().size() == 0)
								cascades[c3].removeBottom();
						}else if(placeOfCard2 > 2){
							if(placeOfCard2 == 3){
								if(cells[index2].add(oc.getTop()))
									oc.removeTop();
								if(cascades[c3].getBottom().size() == 0)
									cascades[c3].removeBottom();
							}else if(placeOfCard2 == 4){
								if(foundations[index2-4].add(oc.getTop()))
									oc.removeTop();
								if(cascades[c3].getBottom().size() == 0)
									cascades[c3].removeBottom();
							}else{
								if(cascades[index2 - 8].add(oc,false))
									cascades[c3].removeBottom();
							}
						}
					}else if(cl != null){
						if(placeOfCard2 == 0){
							c = getCindex(index2);
						}else if(placeOfCard2 == 1){
							cl2 = getCellindex(index2);
						}else if(placeOfCard2 == 2){
							f = getFoundationindex(index2);
						}
						
						if(c != -1){
							oc = new OrderedCascade();
							oc.add(cl.get());
							cascades[c].add(oc,false);
							cl.remove();
						}else if(cl2 != -1){
							if(cells[cl2].get() == null)
								cells[cl2].add(cl.remove());
						}else if(f != -1){
							if(foundations[f].add(cl.get()))
								cl.remove();
						}else if(placeOfCard2 > 2){
							if(placeOfCard2 == 3){
								if(cells[index2].get() == null)
									cells[cl2].add(cl.remove());
							}else if(placeOfCard2 == 4){
								if(foundations[index2-4].add(cl.get()))
									cl.remove();
							}else{
								oc = new OrderedCascade();
								oc.add(cl.get());
								cascades[index2 - 8].add(oc,false);
								cl.remove();
							}
						}						
					}
				}
			}
			Selected = null;
		}
		this.repaint();
		setup();
		}
}
